| @@ -0,0 +1,51 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from __future__ import division | |
| 4 | + | |
| 5 | +import random | |
| 6 | + | |
| 7 | +from utils.algorithm.b64 import b64_decrypt, b64_encrypt | |
| 8 | +from utils.algorithm.rsalg import rsa_decrypt, rsa_encrypt | |
| 9 | +from utils.error.response_utils import response | |
| 10 | + | |
| 11 | + | |
| 12 | +CIPHER_ALGORITHM = ('B64', 'RSA') | |
| 13 | + | |
| 14 | +CIPHER_PREFIX = { | |
| 15 | + 'B64': 'alg1', | |
| 16 | + 'RSA': 'alg2', | |
| 17 | +} | |
| 18 | + | |
| 19 | + | |
| 20 | +def encrypt(request): | |
| 21 | +    plaintext = request.POST.get('plaintext', '') | |
| 22 | + | |
| 23 | + alg = random.choice(CIPHER_ALGORITHM) | |
| 24 | + | |
| 25 | + if alg == 'B64': | |
| 26 | + ciphertext = b64_encrypt(plaintext) | |
| 27 | + elif alg == 'RSA': | |
| 28 | + ciphertext = rsa_encrypt(plaintext) | |
| 29 | + else: | |
| 30 | + ciphertext = plaintext | |
| 31 | + | |
| 32 | +    return response(200, data={ | |
| 33 | + 'ciphertext': u'%s+%s' % (CIPHER_PREFIX.get(alg, ''), ciphertext), | |
| 34 | + }) | |
| 35 | + | |
| 36 | + | |
| 37 | +def decrypt(request): | |
| 38 | +    ciphertext = request.POST.get('ciphertext', '') | |
| 39 | + | |
| 40 | +    alg, ciphertext = ciphertext.split('+', 1) | |
| 41 | + | |
| 42 | + if alg == CIPHER_PREFIX['B64']: | |
| 43 | + plaintext = b64_decrypt(ciphertext) | |
| 44 | + elif alg == CIPHER_PREFIX['RSA']: | |
| 45 | + plaintext = rsa_decrypt(ciphertext) | |
| 46 | + else: | |
| 47 | + plaintext = ciphertext | |
| 48 | + | |
| 49 | +    return response(200, data={ | |
| 50 | + 'plaintext': plaintext, | |
| 51 | + }) | 
| @@ -0,0 +1,33 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from __future__ import division | |
| 4 | + | |
| 5 | +from mch.models import BrandInfo, DistributorInfo, ModelInfo | |
| 6 | +from utils.error.response_utils import response | |
| 7 | + | |
| 8 | + | |
| 9 | +def brands_list(request): | |
| 10 | + brands = BrandInfo.objects.filter(status=True) | |
| 11 | + brands = [brand.data for brand in brands] | |
| 12 | + | |
| 13 | +    return response(200, data={ | |
| 14 | + 'brands': brands, | |
| 15 | + }) | |
| 16 | + | |
| 17 | + | |
| 18 | +def models_list(request): | |
| 19 | + models = ModelInfo.objects.filter(status=True) | |
| 20 | + models = [model.data for model in models] | |
| 21 | + | |
| 22 | +    return response(200, data={ | |
| 23 | + 'models': models, | |
| 24 | + }) | |
| 25 | + | |
| 26 | + | |
| 27 | +def distributors_list(request): | |
| 28 | + distributors = DistributorInfo.objects.filter(status=True) | |
| 29 | + distributors = [distributor.data for distributor in distributors] | |
| 30 | + | |
| 31 | +    return response(200, data={ | |
| 32 | + 'distributors': distributors, | |
| 33 | + }) | 
| @@ -4,6 +4,7 @@ from django.conf.urls import url | ||
| 4 | 4 |  | 
| 5 | 5 | from account import views as account_views | 
| 6 | 6 | from account import tourguide_views | 
| 7 | +from api import encrypt_views, mch_views | |
| 7 | 8 | from box import views as box_views | 
| 8 | 9 | from geo import views as geo_views | 
| 9 | 10 | from group import views as group_views | 
| @@ -181,3 +182,15 @@ urlpatterns += [ | ||
| 181 | 182 | urlpatterns += [ | 
| 182 | 183 | url(r'^box/loginqr$', box_views.login_qrcode_api, name='login_qrcode_api'), # 二维码登录 | 
| 183 | 184 | ] | 
| 185 | + | |
| 186 | +# Kodo | |
| 187 | +urlpatterns += [ | |
| 188 | + url(r'^brands$', mch_views.brands_list, name='brands_list'), | |
| 189 | + url(r'^models$', mch_views.models_list, name='models_list'), | |
| 190 | + url(r'^distributors$', mch_views.distributors_list, name='distributors_list'), | |
| 191 | +] | |
| 192 | + | |
| 193 | +urlpatterns += [ | |
| 194 | + url(r'^encrypt$', encrypt_views.encrypt, name='encrypt'), | |
| 195 | + url(r'^decrypt$', encrypt_views.decrypt, name='decrypt'), | |
| 196 | +] | 
| @@ -0,0 +1,22 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from django.contrib import admin | |
| 4 | + | |
| 5 | +from mch.models import BrandInfo, DistributorInfo, ModelInfo | |
| 6 | + | |
| 7 | + | |
| 8 | +class BrandInfoAdmin(admin.ModelAdmin): | |
| 9 | +    list_display = ('brand_id', 'brand_name', 'brand_descr', 'position', 'status', 'created_at', 'updated_at') | |
| 10 | + | |
| 11 | + | |
| 12 | +class ModelInfoAdmin(admin.ModelAdmin): | |
| 13 | +    list_display = ('model_id', 'model_name', 'model_descr', 'position', 'status', 'created_at', 'updated_at') | |
| 14 | + | |
| 15 | + | |
| 16 | +class DistributorInfoAdmin(admin.ModelAdmin): | |
| 17 | +    list_display = ('distributor_id', 'distributor_name', 'distributor_descr', 'position', 'status', 'created_at', 'updated_at') | |
| 18 | + | |
| 19 | + | |
| 20 | +admin.site.register(BrandInfo, BrandInfoAdmin) | |
| 21 | +admin.site.register(ModelInfo, ModelInfoAdmin) | |
| 22 | +admin.site.register(DistributorInfo, DistributorInfoAdmin) | 
| @@ -0,0 +1,8 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +from __future__ import unicode_literals | |
| 3 | + | |
| 4 | +from django.apps import AppConfig | |
| 5 | + | |
| 6 | + | |
| 7 | +class MchConfig(AppConfig): | |
| 8 | + name = 'mch' | 
| @@ -0,0 +1,68 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.3 on 2017-12-30 13:37 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | +import shortuuidfield.fields | |
| 7 | + | |
| 8 | + | |
| 9 | +class Migration(migrations.Migration): | |
| 10 | + | |
| 11 | + initial = True | |
| 12 | + | |
| 13 | + dependencies = [ | |
| 14 | + ] | |
| 15 | + | |
| 16 | + operations = [ | |
| 17 | + migrations.CreateModel( | |
| 18 | + name='BrandInfo', | |
| 19 | + fields=[ | |
| 20 | +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
| 21 | +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), | |
| 22 | +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), | |
| 23 | +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), | |
| 24 | +                ('brand_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u54c1\u724c\u552f\u4e00\u6807\u8bc6', max_length=22, unique=True)), | |
| 25 | +                ('brand_name', models.CharField(blank=True, help_text='\u54c1\u724c\u540d\u79f0', max_length=255, null=True, verbose_name='brand_name')), | |
| 26 | +                ('brand_descr', models.TextField(blank=True, help_text='\u54c1\u724c\u63cf\u8ff0', max_length=255, null=True, verbose_name='brand_descr')), | |
| 27 | +                ('position', models.IntegerField(default=1, help_text='\u6392\u5e8f', verbose_name='position')), | |
| 28 | + ], | |
| 29 | +            options={ | |
| 30 | + 'verbose_name': '\u54c1\u724c\u4fe1\u606f', | |
| 31 | + 'verbose_name_plural': '\u54c1\u724c\u4fe1\u606f', | |
| 32 | + }, | |
| 33 | + ), | |
| 34 | + migrations.CreateModel( | |
| 35 | + name='DistributorInfo', | |
| 36 | + fields=[ | |
| 37 | +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
| 38 | +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), | |
| 39 | +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), | |
| 40 | +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), | |
| 41 | +                ('distributor_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', max_length=22, unique=True)), | |
| 42 | +                ('distributor_name', models.CharField(blank=True, help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='distributor_name')), | |
| 43 | +                ('distributor_descr', models.TextField(blank=True, help_text='\u7ecf\u9500\u5546\u63cf\u8ff0', max_length=255, null=True, verbose_name='distributor_descr')), | |
| 44 | +                ('position', models.IntegerField(default=1, help_text='\u6392\u5e8f', verbose_name='position')), | |
| 45 | + ], | |
| 46 | +            options={ | |
| 47 | + 'verbose_name': '\u7ecf\u9500\u5546\u4fe1\u606f', | |
| 48 | + 'verbose_name_plural': '\u7ecf\u9500\u5546\u4fe1\u606f', | |
| 49 | + }, | |
| 50 | + ), | |
| 51 | + migrations.CreateModel( | |
| 52 | + name='ModelInfo', | |
| 53 | + fields=[ | |
| 54 | +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
| 55 | +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), | |
| 56 | +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), | |
| 57 | +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), | |
| 58 | +                ('model_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', max_length=22, unique=True)), | |
| 59 | +                ('model_name', models.CharField(blank=True, help_text='\u578b\u53f7\u540d\u79f0', max_length=255, null=True, verbose_name='model_name')), | |
| 60 | +                ('model_descr', models.TextField(blank=True, help_text='\u578b\u53f7\u63cf\u8ff0', max_length=255, null=True, verbose_name='model_descr')), | |
| 61 | +                ('position', models.IntegerField(default=1, help_text='\u6392\u5e8f', verbose_name='position')), | |
| 62 | + ], | |
| 63 | +            options={ | |
| 64 | + 'verbose_name': '\u578b\u53f7\u4fe1\u606f', | |
| 65 | + 'verbose_name_plural': '\u578b\u53f7\u4fe1\u606f', | |
| 66 | + }, | |
| 67 | + ), | |
| 68 | + ] | 
| @@ -0,0 +1,75 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from django.db import models | |
| 4 | +from django.utils.translation import ugettext_lazy as _ | |
| 5 | +from models_ext import BaseModelMixin | |
| 6 | +from shortuuidfield import ShortUUIDField | |
| 7 | + | |
| 8 | + | |
| 9 | +class BrandInfo(BaseModelMixin): | |
| 10 | + brand_id = ShortUUIDField(_(u'brand_id'), max_length=32, help_text=u'品牌唯一标识', db_index=True, unique=True) | |
| 11 | + brand_name = models.CharField(_(u'brand_name'), max_length=255, blank=True, null=True, help_text=u'品牌名称') | |
| 12 | + brand_descr = models.TextField(_(u'brand_descr'), max_length=255, blank=True, null=True, help_text=u'品牌描述') | |
| 13 | + | |
| 14 | + position = models.IntegerField(_(u'position'), default=1, help_text=u'排序') | |
| 15 | + | |
| 16 | + class Meta: | |
| 17 | + verbose_name = _(u'品牌信息') | |
| 18 | + verbose_name_plural = _(u'品牌信息') | |
| 19 | + | |
| 20 | + def __unicode__(self): | |
| 21 | + return unicode(self.pk) | |
| 22 | + | |
| 23 | + @property | |
| 24 | + def data(self): | |
| 25 | +        return { | |
| 26 | + 'brand_id': self.brand_id, | |
| 27 | + 'brand_name': self.brand_name, | |
| 28 | + 'brand_descr': self.brand_descr, | |
| 29 | + } | |
| 30 | + | |
| 31 | + | |
| 32 | +class ModelInfo(BaseModelMixin): | |
| 33 | + model_id = ShortUUIDField(_(u'model_id'), max_length=32, help_text=u'型号唯一标识', db_index=True, unique=True) | |
| 34 | + model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称') | |
| 35 | + model_descr = models.TextField(_(u'model_descr'), max_length=255, blank=True, null=True, help_text=u'型号描述') | |
| 36 | + | |
| 37 | + position = models.IntegerField(_(u'position'), default=1, help_text=u'排序') | |
| 38 | + | |
| 39 | + class Meta: | |
| 40 | + verbose_name = _(u'型号信息') | |
| 41 | + verbose_name_plural = _(u'型号信息') | |
| 42 | + | |
| 43 | + def __unicode__(self): | |
| 44 | + return unicode(self.pk) | |
| 45 | + | |
| 46 | + @property | |
| 47 | + def data(self): | |
| 48 | +        return { | |
| 49 | + 'model_id': self.model_id, | |
| 50 | + 'model_name': self.model_name, | |
| 51 | + 'model_descr': self.model_descr, | |
| 52 | + } | |
| 53 | + | |
| 54 | + | |
| 55 | +class DistributorInfo(BaseModelMixin): | |
| 56 | + distributor_id = ShortUUIDField(_(u'distributor_id'), max_length=32, help_text=u'经销商唯一标识', db_index=True, unique=True) | |
| 57 | + distributor_name = models.CharField(_(u'distributor_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称') | |
| 58 | + distributor_descr = models.TextField(_(u'distributor_descr'), max_length=255, blank=True, null=True, help_text=u'经销商描述') | |
| 59 | + | |
| 60 | + position = models.IntegerField(_(u'position'), default=1, help_text=u'排序') | |
| 61 | + | |
| 62 | + class Meta: | |
| 63 | + verbose_name = _(u'经销商信息') | |
| 64 | + verbose_name_plural = _(u'经销商信息') | |
| 65 | + | |
| 66 | + def __unicode__(self): | |
| 67 | + return unicode(self.pk) | |
| 68 | + | |
| 69 | + @property | |
| 70 | + def data(self): | |
| 71 | +        return { | |
| 72 | + 'distributor_id': self.distributor_id, | |
| 73 | + 'distributor_name': self.distributor_name, | |
| 74 | + 'distributor_descr': self.distributor_descr, | |
| 75 | + } | 
| @@ -0,0 +1,7 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +from __future__ import unicode_literals | |
| 3 | + | |
| 4 | +from django.test import TestCase | |
| 5 | + | |
| 6 | + | |
| 7 | +# Create your tests here. | 
| @@ -0,0 +1,7 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +from __future__ import unicode_literals | |
| 3 | + | |
| 4 | +from django.shortcuts import render | |
| 5 | + | |
| 6 | + | |
| 7 | +# Create your views here. | 
| @@ -46,10 +46,12 @@ INSTALLED_APPS = ( | ||
| 46 | 46 | 'django_rlog', | 
| 47 | 47 | 'django_uniapi', | 
| 48 | 48 | 'django_we', | 
| 49 | + 'djadmin', | |
| 49 | 50 | 'api', | 
| 50 | 51 | 'account', | 
| 51 | 52 | 'box', | 
| 52 | 53 | 'group', | 
| 54 | + 'mch', | |
| 53 | 55 | 'message', | 
| 54 | 56 | 'miniapp', | 
| 55 | 57 | 'operation', | 
| @@ -6,6 +6,7 @@ Pillow==4.3.0 | ||
| 6 | 6 | StatusCode==1.0.0 | 
| 7 | 7 | TimeConvert==1.4.1 | 
| 8 | 8 | cryptography==1.5.2 | 
| 9 | +django-admin==1.1.0 | |
| 9 | 10 | django-curtail-uuid==1.0.0 | 
| 10 | 11 | django-detect==1.0.5 | 
| 11 | 12 | django-file-md5==1.0.1 | 
| @@ -20,7 +21,7 @@ django-rlog==1.0.7 | ||
| 20 | 21 | django-shortuuidfield==0.1.3 | 
| 21 | 22 | django-six==1.0.4 | 
| 22 | 23 | django-uniapi==1.0.0 | 
| 23 | -django-we==1.0.16 | |
| 24 | +django-we==1.1.2 | |
| 24 | 25 | djangorestframework==3.7.2 | 
| 25 | 26 | furl==1.0.1 | 
| 26 | 27 | hiredis==0.2.0 | 
| @@ -38,7 +39,7 @@ pywe-sign==1.0.6 | ||
| 38 | 39 | pywe-xml==1.0.0 | 
| 39 | 40 | qiniu==7.1.9 | 
| 40 | 41 | redis==2.10.6 | 
| 41 | -redis-extensions==1.1.3 | |
| 42 | +redis-extensions==1.1.6 | |
| 42 | 43 | requests==2.18.4 | 
| 43 | 44 | rlog==0.3 | 
| 44 | 45 | shortuuid==0.5.0 | 
| @@ -0,0 +1,13 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +import base64 | |
| 4 | + | |
| 5 | +from CodeConvert import CodeConvert as cc | |
| 6 | + | |
| 7 | + | |
| 8 | +def b64_encrypt(plaintext): | |
| 9 | + return base64.urlsafe_b64encode(cc.Convert2Utf8(plaintext)) | |
| 10 | + | |
| 11 | + | |
| 12 | +def b64_decrypt(ciphertext): | |
| 13 | + return cc.Convert2Unicode(base64.urlsafe_b64decode(cc.Convert2Utf8(ciphertext))) | 
| @@ -0,0 +1,18 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +import base64 | |
| 4 | + | |
| 5 | +import rsa | |
| 6 | +from CodeConvert import CodeConvert as cc | |
| 7 | + | |
| 8 | + | |
| 9 | +pubkey = rsa.PublicKey(7733936986002684982484845608354489436048239676995253266549456282870195715569430535348099548536388503919509506510435040149560886821029985877148893951171111, 65537) | |
| 10 | +privkey = rsa.PrivateKey(7733936986002684982484845608354489436048239676995253266549456282870195715569430535348099548536388503919509506510435040149560886821029985877148893951171111, 65537, 316971401565576878144472516350155768882090601834219605321449556369521730928872332388800749109622843453327077688969025635980606763507018292148749534091473, 4517492317789178911663214752269837474466539823144998211438927363654134055916886851, 1711997816918835594017245862832442114582648667392542139046338517030653261) | |
| 11 | + | |
| 12 | + | |
| 13 | +def rsa_encrypt(plaintext): | |
| 14 | + return base64.urlsafe_b64encode(rsa.encrypt(cc.Convert2Utf8(plaintext), pubkey)) | |
| 15 | + | |
| 16 | + | |
| 17 | +def rsa_decrypt(ciphertext): | |
| 18 | + return rsa.decrypt(base64.urlsafe_b64decode(cc.Convert2Utf8(ciphertext)), privkey) |